#ifndef MODBUS_H_
#define MODUBS_H_

#include "serial.h"

#define HEADER_LENGTH_RTU       0
#define PRESET_QUERY_SIZE_RTU   6
#define CHECKSUM_SIZE_RTU       2

#define MIN_QUERY_SIZE          32
#define MAX_PACKET_SIZE         256
#define MAX_SLAVE_ADDR			248
#define MAX_READ_STATUS         1000
#define MAX_READ_REGS           120
#define MAX_WRITE_STATUS        1000
#define MAX_WRITE_REGS          120
#define ERROR_RESPONSE          5
#define MAX_START_ADDRESS		65535

/* Time out between trames in microsecond */
#define TIME_OUT_BEGIN_OF_TRAME 500000
#define TIME_OUT_END_OF_TRAME   500000

#define EXCEPTION           -0x01
#define WRITE_FAILURE		-0x02
#define ILLEGAL_SLAVE		-0x03
#define READ_FAILURE	    -0x04
#define TOO_LESS_DATAS      -0x05
#define FUNCTION_ERROR      -0x06
#define COMM_TIME_OUT       -0x0C
#define SELECT_FAILURE		-0x0E
#define TOO_MANY_DATAS      -0x0F
#define ILLEGAL_CRC         -0x10
#define ILLEGAL_DATA_ADDRESS -0x11
#define ILLEGAL_DATA_VALUE	 -0x12
#define ILLEGAL_DATA_COUNT	 -0x13
#define SLAVE_DEVICE_FAILURE -0x14
#define POINT_IS_NULL			-0x15
#define ARRAY_IS_SHORT		-0x16


#ifndef FALSE
#define FALSE 0
#endif

#ifndef TRUE
#define TRUE 1
#endif


typedef enum { RTU } type_com_t;

class CModbusParam {
public:
	friend class CModbus;
   	 void  ModbusInitRTU( const char *deviceName,int iBaud, const char *cParity, int iDataBit,
		int iStopBit);
	int ModbusConnect();
	int ModbusClose();
   	 ~CModbusParam();
	
private:
	int _ModbusConnectRTU();
	
	/* Communication : RTU or TCP */
	type_com_t typeCom;
	/* Device: "/dev/ttyS0" */
	char device[20];
	/* Bauds: 19200 */
	int baud;
	/* Parity: "even", "odd", "none" */
	char parity[5];
	/* Data bit */
	int dataBit;
	/* Stop bit */
	int stopBit;
	/* Save old termios settings */
	//struct termios oldTios;
	CSerial *serial;
	/* Descriptor (tty or socket) */
	int fd;
	/* Header length used for offset */
	int headerLength;
	/* Checksum size RTU = 2 and TCP = 0 */
	int checksumSize;
} ;

class CModbus
{
public:
	int ReadCoilStatus(CModbusParam *mbParam, int slave,
		     int startAddr, int count, int *dest);
	int ReadInputStatus(CModbusParam *mbParam, int slave,
		      int startAddr, int count, int *dest);
	int ReadHoldingRegisters(CModbusParam *mbParam, int slave,
			   int startAddr, int count, int *dest);
	int ReadInputRegisters(CModbusParam *mbParam, int slave,
			 int startAddr, int count, int *dest);
	int ForceSingleCoil(CModbusParam *mbParam, int slave,
		      int coilAddr, int state);
	int PresetSingleRegister(CModbusParam *mbParam, int slave,
			   int regAddr, int value);
	int ForceMultipleCoils(CModbusParam *mbParam, int slave,
			 int startAddr, int coil_count, int *data);
	int PresetMultipleRegisters(CModbusParam *mbParam, int slave,
			      int startAddr, int regCount, int *data);

private:
	int _BuildPackage( int slave,int function, int startAddr, int count, 
		unsigned char *package);
	int _ComputeReturnSize(int function,int count);
	int _SendQuery(CModbusParam *mbParam, unsigned char * query,int querySize);
	int _ReceiveData(CModbusParam *mbParam,unsigned char *response,int responseSize,
		unsigned char *query);
	int _ReadBitIO(CModbusParam *mbParam, int function,int slave,
			     int startAddr, int count, int *dest);
	int _ReadRegIO(CModbusParam *mbParam, int function,int slave,
			     int startAddr, int count, int *dest);
	int _SendAndReceive(CModbusParam *mbParam, int function,int slave,
			     int startAddr, int count, unsigned char  *response);
	int _WriteSingle(CModbusParam *mbParam, int slave, int function,
		      int startAddr, int value);
	int _WriteMultiple(CModbusParam *mbParam, int slave,int function,
			 int startAddr, int count,int byteSize,  unsigned char *data);
};


#endif //MODBUS_H_
